//
// Created by RainbowSea on 2025/7/1.
//

#include <queue>
#include <iostream>
#include "YaXue.h"

YaXue::YaXue(uint64_t origin_blood, uint64_t target_blood)
        : _origin_blood(origin_blood), _target_blood(target_blood) {

}

void YaXue::setAttackVec(vector<uint64_t> &attack_vec) {
    _attack_vec = attack_vec;
    _max_attack = *std::max_element(attack_vec.begin(), attack_vec.end());
}

void YaXue::setShieldVec(vector<uint64_t> &shield_vec) {
    _shield_vec = shield_vec;
}

void YaXue::setBloodReturningVec(vector<uint64_t> &br_vec) {
    _br_vec = br_vec;
}

void YaXue::run(uint32_t max_step) {
    _is_run = true;
    _que.emplace(_origin_blood);

    while (_is_run && !_que.empty()) {
        auto now_status = _que.front();
        _que.pop();

        if (now_status.current_blood <= _target_blood) {
            cout << "成功！！！！！！！" << endl;
            std::map<StepType, vector<uint32_t>> cnt;
            cnt[Attack] = vector<uint32_t>(_attack_vec.size(), 0);
            cnt[Shield] = vector<uint32_t>(_shield_vec.size(), 0);
            cnt[BloodReturning] = vector<uint32_t>(_br_vec.size(), 0);

            uint32_t p = 0;
            for (auto &step: now_status.history) {
                cnt[step.type][step.vec_index]++;
                switch (step.type) {
                    case Attack:
                        cout << p << ": 攻击 " << step.vec_index << " = " << _attack_vec[step.vec_index] << endl;
                        break;
                    case Shield:
                        cout << p << ": 加盾 " << step.vec_index << " = " << _shield_vec[step.vec_index] << endl;
                        break;
                    case BloodReturning:
                        cout << p << ":回血 " << step.vec_index << " = " << _br_vec[step.vec_index] << endl;
                        break;
                }
                p++;
            }
            cout << now_status.current_blood << ", " << now_status.current_shield << endl;
            return;
        }
        tryDoAttack(now_status);
        if (now_status.current_blood < _max_attack) {
            tryDoShield(now_status);
            tryDoReturning(now_status);
        }
    }
}

void YaXue::tryDoAttack(YaXue::Status now_status) {
    auto current_blood = now_status.current_blood;
    for (size_t i = 0; i < _attack_vec.size(); i++) {
        auto atk = _attack_vec[i];
        if (now_status.getAll() > atk) {
            auto status = now_status;

            if (status.current_shield > atk) {
                status.current_shield -= atk;
                atk = 0;
            } else {
                atk -= status.current_shield;
                status.current_shield = 0;
            }
            status.current_blood -= atk;
            status.history.emplace_back(Attack, i);
            _que.push(status);
        }
    }
}

void YaXue::tryDoShield(YaXue::Status now_status) {
    auto current_blood = now_status.current_blood;
    for (size_t i = 0; i < _shield_vec.size(); i++) {
        auto shield = _shield_vec[i];

        auto status = now_status;
        status.current_shield += shield;
        status.history.emplace_back(Shield, i);
        _que.push(status);
    }
}

void YaXue::tryDoReturning(YaXue::Status now_status) {
    auto current_blood = now_status.current_blood;
    if (now_status.getBlood() >= _origin_blood) {
        return;
    }
    for (size_t i = 0; i < _br_vec.size(); i++) {
        auto br = _br_vec[i];

        auto status = now_status;
        status.current_blood += br;
        status.current_blood = max(status.current_blood, _origin_blood);

        status.history.emplace_back(BloodReturning, i);
        _que.push(status);
    }
}


YaXue::Status::Status(uint64_t currentBlood) : current_blood(currentBlood) {}

YaXue::Step::Step(YaXue::StepType type, uint32_t vecIndex) : type(type), vec_index(vecIndex) {}
